package com.zx.auth.block.component;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zx.auth.block.modle.OAuth2RegisteredClient;
import com.zx.auth.block.repository.OAuth2RegisteredClientRepository;
import com.zx.auth.block.repository.custom.OAuth2RegisteredClientCustomRepository;
import com.zx.core.context.TenantContextHolder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.time.ZoneId;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * description: 根据用户获取用户信息和用户权限 <br>
 * create: 2025-04-26 15:18
 *
 * @author zhou  xun
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class CustomRegisteredClientRepository implements RegisteredClientRepository {
    private final OAuth2RegisteredClientRepository oAuth2RegisteredClientRepository;
    private final OAuth2RegisteredClientCustomRepository oAuth2RegisteredClientCustomRepository;
    private final ObjectMapper objectMapper;

    @Override
    public void save(RegisteredClient registeredClient) {
        OAuth2RegisteredClient client = convertToOAuth2RegisteredClient(registeredClient);
        oAuth2RegisteredClientRepository.save(client);
    }

    @Override
    public RegisteredClient findById(String id) {
        return oAuth2RegisteredClientRepository.findById(id)
                .map(this::convertToRegisteredClient)
                .orElse(null);
    }

    @Override
    public RegisteredClient findByClientId(String clientId) {
        // 使用自定义方法，根据客户端ID和当前租户ID查找客户端
        List<OAuth2RegisteredClient> clients = oAuth2RegisteredClientCustomRepository.findByClientIdAndTenantId(clientId, TenantContextHolder.getTenantId());
        return clients.isEmpty() ? null : convertToRegisteredClient(clients.get(0));
    }

    private RegisteredClient convertToRegisteredClient(OAuth2RegisteredClient client) {
        try {
            RegisteredClient.Builder builder = RegisteredClient.withId(client.getId())
                    .clientId(client.getClientId())
                    .clientIdIssuedAt(client.getClientIdIssuedAt() != null ?
                            // 明确指定东八区转换
                            client.getClientIdIssuedAt().atZone(ZoneId.of("Asia/Shanghai")).toInstant() : null)
                    .clientSecret(client.getClientSecret())
                    .clientSecretExpiresAt(client.getClientSecretExpiresAt() != null ?
                            client.getClientSecretExpiresAt().atZone(ZoneId.of("Asia/Shanghai")).toInstant() : null)
                    .clientName(client.getClientName());

            // 设置客户端认证方法
            if (StringUtils.hasText(client.getClientAuthenticationMethods())) {
                Arrays.stream(client.getClientAuthenticationMethods().split(","))
                        .map(String::trim)
                        .map(ClientAuthenticationMethod::new)
                        .forEach(builder::clientAuthenticationMethod);
            }

            // 设置授权类型
            if (StringUtils.hasText(client.getAuthorizationGrantTypes())) {
                Arrays.stream(client.getAuthorizationGrantTypes().split(","))
                        .map(String::trim)
                        .map(AuthorizationGrantType::new)
                        .forEach(builder::authorizationGrantType);
            }

            // 设置重定向URI
            if (StringUtils.hasText(client.getRedirectUris())) {
                Arrays.stream(client.getRedirectUris().split(","))
                        .map(String::trim)
                        .forEach(builder::redirectUri);
            }

            // 设置登出重定向URI
            if (StringUtils.hasText(client.getPostLogoutRedirectUris())) {
                Arrays.stream(client.getPostLogoutRedirectUris().split(","))
                        .map(String::trim)
                        .forEach(builder::postLogoutRedirectUri);
            }

            // 设置scope
            if (StringUtils.hasText(client.getScopes())) {
                builder.scopes(scopes ->
                        scopes.addAll(Arrays.stream(client.getScopes().split(","))
                                .map(String::trim)
                                .collect(Collectors.toSet())
                        ));
            }

            // 设置客户端设置
            if (StringUtils.hasText(client.getClientSettings())) {
                Map<String, Object> settingsMap = objectMapper.readValue(client.getClientSettings(), Map.class);
                ClientSettings clientSettings = ClientSettings.withSettings(settingsMap).build();
                builder.clientSettings(clientSettings);
            }

            // 设置token设置
            if (StringUtils.hasText(client.getTokenSettings())) {
                Map<String, Object> settingsMap = objectMapper.readValue(client.getTokenSettings(), Map.class);
                TokenSettings tokenSettings = TokenSettings.withSettings(settingsMap).build();
                builder.tokenSettings(tokenSettings);
            }

            return builder.build();
        } catch (JsonProcessingException e) {
            log.error("Failed to convert OAuth2RegisteredClient to RegisteredClient", e);
            throw new IllegalStateException("Failed to parse client settings", e);
        }
    }

    private OAuth2RegisteredClient convertToOAuth2RegisteredClient(RegisteredClient registeredClient) {
        try {
            OAuth2RegisteredClient client = OAuth2RegisteredClient.builder()
                    .id(registeredClient.getId())
                    .clientId(registeredClient.getClientId())
                    .clientIdIssuedAt(registeredClient.getClientIdIssuedAt() != null ?
                            registeredClient.getClientIdIssuedAt().atZone(ZoneId.of("Asia/Shanghai")).toLocalDateTime() : null)
                    .clientSecret(registeredClient.getClientSecret())
                    .clientSecretExpiresAt(registeredClient.getClientSecretExpiresAt() != null ?
                            registeredClient.getClientSecretExpiresAt().atZone(ZoneId.of("Asia/Shanghai")).toLocalDateTime() : null)
                    .clientName(registeredClient.getClientName())
                    .tenantId(TenantContextHolder.getTenantId())
                    .build();

            // 设置客户端认证方法
            if (registeredClient.getClientAuthenticationMethods() != null) {
                client.setClientAuthenticationMethods(
                        registeredClient.getClientAuthenticationMethods().stream()
                                .map(ClientAuthenticationMethod::getValue)
                                .collect(Collectors.joining(","))
                );
            }

            // 设置授权类型
            if (registeredClient.getAuthorizationGrantTypes() != null) {
                client.setAuthorizationGrantTypes(
                        registeredClient.getAuthorizationGrantTypes().stream()
                                .map(AuthorizationGrantType::getValue)
                                .collect(Collectors.joining(","))
                );
            }

            // 设置重定向URI
            if (registeredClient.getRedirectUris() != null) {
                client.setRedirectUris(
                        String.join(",", registeredClient.getRedirectUris())
                );
            }

            // 设置登出重定向URI
            if (registeredClient.getPostLogoutRedirectUris() != null) {
                client.setPostLogoutRedirectUris(
                        String.join(",", registeredClient.getPostLogoutRedirectUris())
                );
            }

            // 设置scope
            if (registeredClient.getScopes() != null) {
                client.setScopes(
                        String.join(",", registeredClient.getScopes())
                );
            }

            // 设置客户端设置
            if (registeredClient.getClientSettings() != null) {
                client.setClientSettings(
                        objectMapper.writeValueAsString(registeredClient.getClientSettings())
                );
            }

            // 设置token设置
            if (registeredClient.getTokenSettings() != null) {
                client.setTokenSettings(
                        objectMapper.writeValueAsString(registeredClient.getTokenSettings())
                );
            }

            return client;
        } catch (JsonProcessingException e) {
            log.error("Failed to convert RegisteredClient to OAuth2RegisteredClient", e);
            throw new IllegalStateException("Failed to serialize client settings", e);
        }
    }
}